package com.kgcx.schedule.service;

import java.sql.Timestamp;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.kgcx.common.client.organization.pojo.Driver;
import com.kgcx.common.constant.Cons;
import com.kgcx.common.constant.ErrorCode;
import com.kgcx.core.utils.HelpUtil;
import com.kgcx.schedule.client.CityClient;
import com.kgcx.schedule.domain.ScheduleRecordDomain;
import com.kgcx.schedule.domain.ScheduleReserveCfgDetailDomain;
import com.kgcx.schedule.model.ScheduleException;

/**
 * 预约类订单派车
 * 
 * @author 袁进勇
 *
 */
public abstract class ScheduleOrderBookService extends ScheduleOrderService {
    public static Boolean SWITCH = false; // 临时开关，等功能切换过来后再删除
    private static final Logger LOG = LoggerFactory.getLogger(ScheduleOrderBookService.class);

    @Value("${kgcx.schedule.failed-msg-id:SMS_117512194}")
    protected String scheduleFailedMsgId;

    @Autowired
    protected CityClient cityClient;

    protected List<Driver> driverList;

    @Override
    protected void prepareRecord(ScheduleRecordDomain record) {
        super.prepareRecord(record);

        record.setSchedule_task(Cons.BOOLEAN_TRUE); // 需要定时任务来调度，不立即调度
        record.setFisrt_schedule_time(calculateScheduleTime(record)); // 预约类订单，根据订单类型和用车时间计算调度时间

        // 用车时间小于可预约最短时间(即理论首次调度时间已经过期了)，立即进行派单
        if (record.getCreate_time().after(record.getFisrt_schedule_time())) {
            record.setSchedule_task(Cons.BOOLEAN_FALSE); // 不需要定时任务来调度，立即调度
            record.setFisrt_schedule_time(record.getCreate_time());
        }

        record.setLatest_schedule_time(record.getFisrt_schedule_time()); // 定时任务扫描时，根据最近派单时间来调度
    }

    /**
     * 根据订单类型和用车时间计算调度时间
     * 
     * @param record
     * @return
     */
    protected abstract Timestamp calculateScheduleTime(ScheduleRecordDomain record);

    @Override
    protected void checkRecord(ScheduleRecordDomain record, ScheduleReserveCfgDetailDomain cfgDetail)
            throws ScheduleException {
        if (!SWITCH) {
            // TODO 后续需要启用预约单功能时，再放开。
            throw new ScheduleException(ErrorCode.SCHEDULE_NO_AVAILABLE_AUTO, "当前没有可用车辆！");
        }

        // 可预约最长时间检查
        Timestamp maxTime = getMaxTime(record);
        if (maxTime.before(record.getPlan_depart_time())) {
            LOG.warn(String.format("订单[%s]，用车时间[%s]大于可预约最长时间[%s]，下单失败！", record.getOrder_no(),
                    HelpUtil.formatDatetime(record.getPlan_depart_time()), HelpUtil.formatDatetime(maxTime)));
            throw new ScheduleException(ErrorCode.SCHEDULE_DEPART_GT_MAX, "用车时间必须小于可预约最长时间！");
        }

        // 预约接机、接站的，用车时间小于可预约最短时间，可以下单成功，立即进行派单。
        if (record.getCreate_time().equals(record.getFisrt_schedule_time())) {
            driverList = getDriverList(record);
            checkReserveQuantity(record, cfgDetail, driverList.size());
        } else {
            checkReserveQuantity(record, cfgDetail);
        }
    }

    @Override
    protected void afterRecordAdded(ScheduleRecordDomain record, ScheduleReserveCfgDetailDomain cfgDetail)
            throws ScheduleException {
        // 预约接机、接站的，用车时间小于可预约最短时间，可以下单成功，立即进行派单。
        if (record.getCreate_time().equals(record.getFisrt_schedule_time())) {
            LOG.info(String.format("订单[%s]，用车时间[%s]小于可预约最短时间[%s]，立即进行派单。", record.getOrder_no(),
                    HelpUtil.formatDatetime(record.getPlan_depart_time()),
                    HelpUtil.formatDatetime(getMinTime(record))));

            scheduleRecord(record, cfgDetail, driverList);
        }
    }

    /**
     * 获取可预约最短时间
     * 
     * @return
     */
    protected abstract Timestamp getMinTime(ScheduleRecordDomain record);

    /**
     * 获取可预约最长时间
     * 
     * @return
     */
    protected abstract Timestamp getMaxTime(ScheduleRecordDomain record);

    @Override
    protected void scheduleFailed(ScheduleRecordDomain record, Driver driver) {
        sendFailedMSGToAdmin(getAdminPhone(record), scheduleFailedMsgId, record);
    }

    protected abstract String getAdminPhone(ScheduleRecordDomain record);
}
